﻿/*
* 
* http协议操作模块：简化了 Get和Post请求。
* 
* */
namespace Common.Net
{
	using System;
	using System.Net;
    using System.Text;
    using System.IO;
    using System.IO.Compression;
    using System.Globalization;
    using System.Text.RegularExpressions;

	/// <summary>
	/// HttpProc 的摘要说明。
	/// </summary>
	public class HttpProc {
		/// <summary>
		/// 创建请求
		/// </summary>
		/// <returns>请求对象</returns>
		private HttpWebRequest CreateRequest() {
			HttpWebRequest 请求;

			请求 = (HttpWebRequest)HttpWebRequest.Create(url);//创建请求
			请求.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; //接受任意文件
			请求.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)"; // 模拟使用IE在浏览

            //Uri uri = new Uri(_strUrl);
            
			请求.CookieContainer = new CookieContainer();//cookie容器，
			请求.Referer = this.RefUrl; //当前页面的引用
            请求.AllowAutoRedirect = this.AllowAutoRedirect;
            //请求.Headers["Host"] = uri.Host;
            //请求.Headers["Accept-Language"] = "	zh-cn,zh;q=0.5";   
			//使用代理
			//WebProxy myProxy = new WebProxy();
			//if (config.Proxy_DEF != "0") {
			//    //使用浏览器的代理
			//    myProxy = (WebProxy)请求.Proxy;
			//    //Console.WriteLine("\nThe actual default Proxy settings are {0}",myProxy.Address);

			//} else {
			//    //使用自定的代码
			//    myProxy.Address = new Uri(String.Format("http://{0}:{1}", config.Proxy_Server, config.Proxy_Port));

			//    myProxy.Credentials = new NetworkCredential(username, password);
			//    if (config.Proxy_Username.Length > 0 & config.Proxy_Pass.Length > 0) {
			//        myProxy.Credentials = new NetworkCredential(config.Proxy_Username, config.Proxy_Pass);
			//    }

			//    请求.Proxy = myProxy;
			//}

			//Console.WriteLine("\nThe Address of the  new Proxy settings are {0}",myProxy.Address);

			//如果附带cookie 就发送
			if (this.cookiePost != null) {
				System.Uri u = new Uri(url);
				//doenet处理cookie的bug：请求的服务器和cookie的Host必须一直，否则不发送或获取！

				//这里修改成一致！
				foreach (System.Net.Cookie c in cookiePost) {
					c.Domain = u.Host;
				}

				请求.CookieContainer.Add(cookiePost);
			}

			//如果需要发送数据，就以Post方式发送
			if (postdata != null && postdata.Length > 0) {
				请求.ContentType = "application/x-www-form-urlencoded";//作为表单请求
				请求.Method = "POST";//方式就是Post

				//发送http数据：朝请求流中写post的数据
				byte[] b = this.encoding.GetBytes(this.postdata);
				请求.ContentLength = b.Length;
				System.IO.Stream sw = null;
				try {
					sw = 请求.GetRequestStream();
					sw.Write(b, 0, b.Length);
                }
                catch (WebException ex)
                {
					this.errorStr = ex.Message;
				} finally {
					if (sw != null) { sw.Close(); }
				}

			}
			return 请求; //返回创建的请求对象

		}

		/// <summary>
		/// 处理请求
		/// </summary>
		/// <returns>返回当前处理的文本</returns>
        public string Proc()
        {

            HttpWebRequest 请求 = CreateRequest();//请求
            if (TimeOut.HasValue)
            {
                请求.Timeout = TimeOut.Value;
                请求.ReadWriteTimeout = TimeOut.Value;
            }

            HttpWebResponse 响应 = null; ;
            System.IO.StreamReader sr = null;

            try
            {
                //这里得到响应
                响应 = (HttpWebResponse)请求.GetResponse();
                this.resHtml = DecodeData(响应); // 这里假定响应的都是html文本
            }
            catch (WebException ex)
            {
                this.errorStr = ex.Message;//发生错误就返回空文本
                return "";
            }
            finally
            {
                if (sr != null) { sr.Close(); }
            }
            //状态码
            this.statusCode = 响应.StatusCode.ToString();
        
            //得到cookie
            if (响应.Cookies.Count > 0)
            {
                this.cookieGet = (响应.Cookies); //得到新的cookie：注意这里没考虑cookie合并的情况
            }
            return this.ResHtml;
        }


        private string DecodeData(HttpWebResponse Response)
        {
            //save data to a memorystream
            MemoryStream bodydata = new MemoryStream();
            byte[] buffer = new byte[1024];
            using (Stream rs = Response.GetResponseStream())
            {
                int read = rs.Read(buffer, 0, buffer.Length);
                while (read > 0)
                {
                    bodydata.Write(buffer, 0, read);
                    read = rs.Read(buffer, 0, buffer.Length);
                }
            }
            byte[] bbodydata = new byte[bodydata.Length];
            bodydata.Seek(0, SeekOrigin.Begin);
            bodydata.Read(bbodydata, 0, bbodydata.Length);

            DecompressHTTPBody(Response.Headers, ref bbodydata);
            this.responseBody = bbodydata;
            this.encoding = GetEntityBodyEncoding(Response.Headers, bbodydata);

            string contentType = Response.Headers["Content-Type"];

            if (contentType != null)
            {
                if (contentType.Contains("text"))
                {
                    return Encoding.GetString(bbodydata, 0, bbodydata.Length);
                }
            }
            return string.Empty;
        }


        public Encoding GetEntityBodyEncoding(WebHeaderCollection headers, byte[] oBody)
        {
            string contentType = headers["Content-Type"];

            if (contentType != null)
            {
                int ind = contentType.IndexOf("charset=");
                try
                {
                    return Encoding.GetEncoding(contentType.Substring(ind + 8));
                }
                catch (Exception)
                {
                }
            }
            Encoding headerEncoding = Encoding.Default;
            if ((oBody != null) && (oBody.Length >= 2))
            {
                if (contentType.Contains("html"))
                {
                    string input = headerEncoding.GetString(oBody, 0, Math.Min(0x1000, oBody.Length));
                    MatchCollection matchs = new Regex("<meta.*charset\\s*=\\s*(?<thecharset>[^\\\"]*)", RegexOptions.IgnoreCase).Matches(input);
                    if ((matchs.Count <= 0) || (matchs[0].Groups.Count <= 0))
                    {
                        return headerEncoding;
                    }
                    try
                    {
                        headerEncoding = Encoding.GetEncoding(matchs[0].Groups[1].Value);
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            return headerEncoding;
        }
        public void DecompressHTTPBody(WebHeaderCollection headers, ref byte[] arrBody)
        {
            if ((arrBody != null) && (arrBody.LongLength > 0L))
            {
                //if (headers["Transfer-Encoding"] == "chunked")
                //{
                //    arrBody = doUnchunk(arrBody);
                //}
                if (headers["Transfer-Encoding"]=="gzip"|| headers["Content-Encoding"]=="gzip")
                {
                    arrBody = Utilities.GzipExpand(arrBody);
                }
                if (headers["Transfer-Encoding"]=="deflate" || headers["Content-Encoding"]== "deflate")
                {
                    arrBody =Utilities. DeflaterExpand(arrBody);
                }
                //if (oHeaders.ExistsAndContains("Transfer-Encoding", "bzip2") || oHeaders.ExistsAndContains("Content-Encoding", "bzip2"))
                //{
                //    arrBody = bzip2Expand(arrBody);
                //}
            }
        }

      
		/// <summary>
		/// 加载验证码
		/// </summary>
		/// <returns>验证码的图象</returns>
		public System.Drawing.Image LoadPWDext() {
	//	this.strUrl = "验证码URL";
			System.Drawing.Image img = null;
			HttpWebRequest 请求 = CreateRequest();
			HttpWebResponse 响应; ;
			try {
				响应 = (HttpWebResponse)请求.GetResponse();
				img = System.Drawing.Image.FromStream(响应.GetResponseStream());//直接作为stream创建图象。
				//得到cookie
			    if (响应.Cookies.Count > 0)
			    {
			        cookieGet = 响应.Cookies;
			    }
			}
            catch (WebException ex)
			{
			    Console.WriteLine(ex.Message);
			}
		    return img;
		}


		#region 构造函数
		public HttpProc() {
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="地址">发送的地址</param>
		/// <param name="要发送的cookie">要发送cookies集合</param>
		public HttpProc(string 地址, CookieCollection 要发送的cookie)
		{
		    url = 地址;
		    cookiePost = 要发送的cookie;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="地址">发送的地址</param>
		/// <param name="发送数据">要发送的数据</param>
		public HttpProc(string 地址, string 发送数据)
		{
		    url = 地址;
		    postdata = 发送数据;

		}


		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="地址">发送的地址</param>
		public HttpProc(string 地址) {
			url = 地址;
		}


		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="地址">发送的地址</param>
		/// <param name="发送数据">要发送的数据</param>
		/// <param name="要发送的cookie">要发送cookies集合</param>
		public HttpProc(string 地址, string 发送数据, CookieCollection 要发送的cookie)
		{
		    url = 地址;
		    postdata = 发送数据;
		    cookiePost = 要发送的cookie;
		}
		#endregion
        private byte[] responseBody;

        public byte[] ResponseBody
        {
            get {
                return responseBody;
            }
        }
		#region 地址
		private string url;
		/// <summary>
		/// 请求http的地址
		/// </summary>
		public string Url {
			get {
				return url;
			}
			set {
				url = value;
			}
		}
		#endregion

		#region 来源地址
		private string refUrl;
		/// <summary>
		/// 当前页面的引用地址
		/// </summary>
		public string RefUrl {
			get {
				return refUrl;
			}
			set {
				refUrl = value;
			}
		}
		#endregion
        bool allowAutoRedirect = true;
        public bool AllowAutoRedirect
        {
            get { return allowAutoRedirect; }
            set { allowAutoRedirect = value; }
        }
		#region 数据
		private string postdata;
		/// <summary>
		/// 发送出去的数据
		/// </summary>
		public string Postdata {
			get { return postdata; }
			set { postdata = value; }
		}
		#endregion

		#region 要发送的cookie集合
		private CookieCollection cookiePost;
		/// <summary>
		/// 发送的cookie集合
		/// </summary>
		public CookieCollection CookiePost {
			get {
				return cookiePost;
			}
			set { cookiePost = value; }
		}
		#endregion

		#region 获取的cookie集合
		private CookieCollection cookieGet = new CookieCollection();
		/// <summary>
		/// 发送的cookie集合
		/// </summary>
		public CookieCollection CookieGet {
			get {
				return cookieGet;
			}
			//set {
			//    _cookieGet = value;
			//}
		}
		#endregion

		#region 代理

	    /// <summary>
	    /// 代理服务器
	    /// </summary>
	    //public IWebProxy Proxy { get; set; }

	    #endregion

		#region 是否发送成功

        public int? TimeOut { get; set; }
		
		#endregion

		#region 响应的html结果
		private string resHtml;
		/// <summary>
		/// 返回的html结果，以文本方式
		/// </summary>
		public string ResHtml {
			get {

				return resHtml;
			}
		}
		#endregion

		#region 响应码
		private string statusCode;
		/// <summary>
		/// 响应代码
		/// </summary>
		public string StatusCode {
			get { return statusCode; }
			set { statusCode = value; }
		}
		#endregion

		#region 错误文本
		private string errorStr;
		/// <summary>
		/// 错误文本
		/// </summary>
		public string ErrorString {
			get { return errorStr; }
			set { errorStr = value; }
		}
		#endregion

		#region 编码
		private  Encoding encoding = System.Text.Encoding.Default;
		public  Encoding Encoding {
			get { return encoding; }
			set { encoding = value; }
		}
		#endregion

	}
}

